/**
 * 
 */
package com.letoo.sso.common.utils.qiniu;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;

/**
 * 七牛的上传、下载服务工具类。
 * 
 * @author dengjie
 *
 */
public class QiniuUtils {

    private static final Logger LOG = LoggerFactory.getLogger(QiniuUtils.class);

    // 设置好账号的ACCESS_KEY和SECRET_KEY.绑定在2进制代码中相对比文本文件中安全。后续可以提供资源中心进行保证安全。
    public static String ACCESS_KEY = "vCBu5e4gSqMgp6xyVQLzEpg5-XmnfWTJpe2OSyYo";
    public static String SECRET_KEY = "HOFDvq6tHgP3b9nlVBWbN5xN8b7RvUSuFTyohG38";

    // 密钥配置
    private static Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);

    public static void main(String[] args) throws IOException {
        upload();
    }

    public static void upload() throws IOException {
        try {
            // 创建上传对象
            UploadManager uploadManager = new UploadManager();
            File file = new File("E:\\\\timg.jpg");
            System.out.println(file.exists());
            // 调用put方法上传
            Response res = uploadManager.put(Files.readAllBytes(Paths.get("E:\\timg.jpg")), "timg.jpg", getUpTokenForSimple("miaomiao-biz-photos"));
            // 打印返回的信息
            System.out.println(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            System.out.println(r.toString());
            try {
                // 响应的文本信息
                System.out.println(r.bodyString());
            } catch (QiniuException e1) {
                // ignore
            }
        }
    }

    /**
     * final类无需修改
     */
    private static UploadManager UPLOADMANAGER = new UploadManager();

    public static Auth getAuth() {
        return auth;
    }

    public static UploadManager getUPLOADMANAGER() {
        return UPLOADMANAGER;
    }

    /**
     * 简单上传，使用默认策略，只需要设置上传的空间名就可以了
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @return 返回token信息
     */
    public static String getUpTokenForSimple(final String bucketname) {
        return auth.uploadToken(bucketname, null, 3600, null);
    }

    /**
     * 覆盖上传，使用覆盖策略
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param fileNameInQiniu
     *            上传空间后需要另存为的文件名字.覆盖上传一定要保证该名字与upload的时候名字一致。
     * @return 返回token信息
     */
    public static String getUpTokenForOverriding(final String bucketname, final String fileNameInQiniu) {
        return auth.uploadToken(bucketname, fileNameInQiniu, 3600, new StringMap().put("insertOnly", "1"));
    }

    /**
     * 支持回调上传，使用默认策略
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param callbackUrl
     *            回调地址。上传成功后，七牛云向"App-Server"发送POST请求的URL。必须是公网上可以正常进行POST请求并能响应"HTTP/1.1 200 OK"的有效URL。另外，为了给客户端有一致的体验，
     *            我们要求callbackUrl 返回包 Content-Type 为 "application/json"，即返回的内容必须是合法的 JSON 文本。出于高可用的考虑，本字段允许设置多个
     *            callbackUrl(用 ; 分隔)，在前一个 callbackUrl 请求失败的时候会依次重试下一个callbackUrl。一个典型例子是
     *            http://<ip1>/callback;http://<ip2>/callback，并同时指定下面的 callbackHost 字段。在 callbackUrl 中使用 ip 的好处是减少了对 dns
     *            解析的依赖，可改善回调的性能和稳定性。
     * @param callbackBody
     *            回调内容信息。上传成功后，七牛云向"App-Server"发送Content-Type: application/x-www-form-urlencoded
     *            的POST请求。该字段"App-Server"可以通过直接读取请求的query来获得，支持魔法变量和自定义变量。callbackBody 要求是合法的 url query
     *            string。如：key=$(key)&hash=$(etag)&w=$(imageInfo.width)&h=$(imageInfo.height)。
     * @return 返回token信息
     */
    public static String getUpTokenForCallback(final String bucketname, final String callbackUrl, final String callbackBody) {
        return auth.uploadToken(bucketname, null, 3600, new StringMap().put("callbackUrl", callbackUrl).put("callbackBody", callbackBody));
    }

    /**
     * 简单上传。上传策略默认。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param filePath
     *            上传的文件地址
     * @param fileNameInQiniu
     *            上传后另存为的文件名
     * @throws IOException
     *             IO异常
     */
    public static void simpleUpload(final String bucketname, final String filePath, final String fileNameInQiniu) throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(filePath, fileNameInQiniu, getUpTokenForSimple(bucketname));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 简单上传。上传策略默认。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param file
     *            文件对象
     * @param fileNameInQiniu
     *            上传后另存为的文件名
     * @throws IOException
     *             IO异常
     */
    public static void simpleUpload(final String bucketname, final File file, final String fileNameInQiniu) throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(file, fileNameInQiniu, getUpTokenForSimple(bucketname));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 简单上传。上传策略默认。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param data
     *            文件二进制流
     * @param fileNameInQiniu
     *            上传后另存为的文件名
     * @throws IOException
     *             IO异常
     */
    public static void simpleUpload(final String bucketname, final byte[] data, final String fileNameInQiniu) throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(data, fileNameInQiniu, getUpTokenForSimple(bucketname));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 覆盖上传。对以前的文件进行覆盖。指定空间key进行覆盖。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param filePath
     *            上传的文件地址
     * @param fileNameInQiniu
     *            指定空间的文件key。
     * @throws IOException
     *             IO异常
     */
    public static void overrideUpload(final String bucketname, final String filePath, final String fileNameInQiniu) throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(filePath, fileNameInQiniu, getUpTokenForOverriding(bucketname, fileNameInQiniu));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 覆盖上传。对以前的文件进行覆盖。指定空间key进行覆盖。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param file
     *            文件对象
     * @param fileNameInQiniu
     *            指定空间的文件key。
     * @throws IOException
     *             IO异常
     */
    public static void overrideUpload(final String bucketname, final File file, final String fileNameInQiniu) throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(file, fileNameInQiniu, getUpTokenForOverriding(bucketname, fileNameInQiniu));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 覆盖上传。对以前的文件进行覆盖。指定空间key进行覆盖。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param data
     *            文件流
     * @param fileNameInQiniu
     *            指定空间的文件key。
     * @throws IOException
     *             IO异常
     */
    public static void overrideUpload(final String bucketname, final byte[] data, final String fileNameInQiniu) throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(data, fileNameInQiniu, getUpTokenForOverriding(bucketname, fileNameInQiniu));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 上传支持回调。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param filePath
     *            上传的文件地址
     * @param fileNameInQiniu
     *            空间另存为的名字
     * @param callbackUrl
     *            回调地址。回调地址。上传成功后，七牛云向"App-Server"发送POST请求的URL。必须是公网上可以正常进行POST请求并能响应"HTTP/1.1 200 OK"的有效URL。另外，
     *            为了给客户端有一致的体验， 我们要求callbackUrl 返回包 Content-Type 为 "application/json"，即返回的内容必须是合法的 JSON
     *            文本。出于高可用的考虑，本字段允许设置多个 callbackUrl(用 ; 分隔)，在前一个 callbackUrl 请求失败的时候会依次重试下一个callbackUrl。一个典型例子是
     *            http://<ip1>/callback;http://<ip2>/callback，并同时指定下面的 callbackHost 字段。在 callbackUrl 中使用 ip 的好处是减少了对 dns
     *            解析的依赖，可改善回调的性能和稳定性。
     * @param callbackBody
     *            回调内容。回调内容信息。上传成功后，七牛云向"App-Server"发送Content-Type: application/x-www-form-urlencoded
     *            的POST请求。该字段"App-Server"可以通过直接读取请求的query来获得，支持魔法变量和自定义变量。callbackBody 要求是合法的 url query
     *            string。如：key=$(key)&hash=$(etag)&w=$(imageInfo.width)&h=$(imageInfo.height)。
     * @throws IOException
     *             IO异常
     */
    public static void callbackUpload(final String bucketname, final String filePath, final String fileNameInQiniu, final String callbackUrl, final String callbackBody)
            throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(filePath, fileNameInQiniu, getUpTokenForCallback(bucketname, callbackUrl, callbackBody));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 上传支持回调。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param file
     *            文件对象
     * @param fileNameInQiniu
     *            空间另存为的名字
     * @param callbackUrl
     *            回调地址。回调地址。上传成功后，七牛云向"App-Server"发送POST请求的URL。必须是公网上可以正常进行POST请求并能响应"HTTP/1.1 200 OK"的有效URL。另外，
     *            为了给客户端有一致的体验， 我们要求callbackUrl 返回包 Content-Type 为 "application/json"，即返回的内容必须是合法的 JSON
     *            文本。出于高可用的考虑，本字段允许设置多个 callbackUrl(用 ; 分隔)，在前一个 callbackUrl 请求失败的时候会依次重试下一个callbackUrl。一个典型例子是
     *            http://<ip1>/callback;http://<ip2>/callback，并同时指定下面的 callbackHost 字段。在 callbackUrl 中使用 ip 的好处是减少了对 dns
     *            解析的依赖，可改善回调的性能和稳定性。
     * @param callbackBody
     *            回调内容。回调内容信息。上传成功后，七牛云向"App-Server"发送Content-Type: application/x-www-form-urlencoded
     *            的POST请求。该字段"App-Server"可以通过直接读取请求的query来获得，支持魔法变量和自定义变量。callbackBody 要求是合法的 url query
     *            string。如：key=$(key)&hash=$(etag)&w=$(imageInfo.width)&h=$(imageInfo.height)。
     * @throws IOException
     *             IO异常
     */
    public static void callbackUpload(final String bucketname, final File file, final String fileNameInQiniu, final String callbackUrl, final String callbackBody)
            throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(file, fileNameInQiniu, getUpTokenForCallback(bucketname, callbackUrl, callbackBody));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }

    /**
     * 上传支持回调。
     * 
     * @param bucketname
     *            上传到的七牛空间名字
     * @param data
     *            文件流
     * @param fileNameInQiniu
     *            空间另存为的名字
     * @param callbackUrl
     *            回调地址。回调地址。上传成功后，七牛云向"App-Server"发送POST请求的URL。必须是公网上可以正常进行POST请求并能响应"HTTP/1.1 200 OK"的有效URL。另外，
     *            为了给客户端有一致的体验， 我们要求callbackUrl 返回包 Content-Type 为 "application/json"，即返回的内容必须是合法的 JSON
     *            文本。出于高可用的考虑，本字段允许设置多个 callbackUrl(用 ; 分隔)，在前一个 callbackUrl 请求失败的时候会依次重试下一个callbackUrl。一个典型例子是
     *            http://<ip1>/callback;http://<ip2>/callback，并同时指定下面的 callbackHost 字段。在 callbackUrl 中使用 ip 的好处是减少了对 dns
     *            解析的依赖，可改善回调的性能和稳定性。
     * @param callbackBody
     *            回调内容。回调内容信息。上传成功后，七牛云向"App-Server"发送Content-Type: application/x-www-form-urlencoded
     *            的POST请求。该字段"App-Server"可以通过直接读取请求的query来获得，支持魔法变量和自定义变量。callbackBody 要求是合法的 url query
     *            string。如：key=$(key)&hash=$(etag)&w=$(imageInfo.width)&h=$(imageInfo.height)。
     * @throws IOException
     *             IO异常
     */
    public static void overrideUpload(final String bucketname, final byte[] data, final String fileNameInQiniu, final String callbackUrl, final String callbackBody)
            throws IOException {
        try {
            // 调用put方法上传
            Response res = UPLOADMANAGER.put(data, fileNameInQiniu, getUpTokenForCallback(bucketname, callbackUrl, callbackBody));
            // 打印返回的信息
            LOG.debug(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            LOG.error(r.toString());
            try {
                // 响应的文本信息
                LOG.debug(r.bodyString());
            } catch (QiniuException e1) {
                LOG.error(e1.toString());
            }
        }
    }
}
